package com.foohoo.benchmark.collection;

import lombok.extern.slf4j.Slf4j;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 测试HashMap不指定大小对性能的影响
 * Benchmark                                     Mode  Cnt    Score      Error  Units
 * HashMapInitialSize.hashMapWithInitialSize     avgt    3  675.181 ±  600.500  us/op
 * HashMapInitialSize.hashMapWithOutInitialSize  avgt    3  996.670 ± 1243.003  us/op
 * 一句话结论: 合理指定了初始大小的HashMap扩容次数更少，可以节省扩容时旧数组复制到新数组的时间
 * 注: HashSet同理
 *
 * @author mzdbxqh
 * @date 2020-10-19 20:39
 **/
@Slf4j
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@Warmup(iterations = 3, time = 1)
@Measurement(iterations = 3, time = 1)
@Fork(1)
@State(Scope.Benchmark)
@Threads(1)
public class HashMapInitialSize {

	private static final int INITIAL_SIZE = 65536;

	private static final int TARGET_SIZE = 49000;

	private static List<User> HOLDER;

	static class User {
		Integer id;
		String name;

		User(Integer id, String name) {
			this.id = id;
			this.name = name;
		}
	}

	@Setup
	public void initialize() {
		HOLDER = new ArrayList<>();
		for (int i = 0; i < TARGET_SIZE; i++) {
			HOLDER.add(new User(i, "user"));
		}
	}

	@Benchmark
	public void hashMapWithInitialSize(Blackhole bh) {
		HashMap<Integer, String> map = new HashMap<>(INITIAL_SIZE);
		for (User i:HOLDER) {
			map.put(i.id, i.name);
		}
		bh.consume(map);
	}

	@Benchmark
	public void hashMapWithOutInitialSize(Blackhole bh) {
		HashMap<Integer, String> map = new HashMap<>();
		for (User i:HOLDER) {
			map.put(i.id, i.name);
		}
		bh.consume(map);
	}
}
